home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / THINKC / 4_0 / GREPSTUF / GREPIO.C < prev    next >
Text File  |  1986-10-31  |  10KB  |  507 lines

  1. /*
  2.     GrepIO - routines for treating TEXT or WORD (MacWrite)
  3.     files as a stream of characters or lines, and for output file
  4.     setup and termination.
  5. */
  6.  
  7. # include    <FileMgr.h>
  8. # include    <StdFilePkg.h>
  9. # include    "Grep.h"
  10.  
  11.  
  12. # define    bufSize    1024    /* input buffer size */
  13. # define    lineLen    65        /* output line len before break */
  14.  
  15.  
  16. typedef Byte ByteBuf[];
  17.  
  18.  
  19. typedef struct
  20. {
  21.     int        version;
  22.     int        paraOffset;
  23.     int        paraCount;
  24. } DocInfo3;
  25.  
  26. typedef struct
  27. {
  28.     int    paraType;
  29.     int    paraLen;
  30. } ParaInfo3;
  31.  
  32.  
  33. typedef struct
  34. {
  35.     long    iArrayPos;
  36.     int        iArrayLen;
  37. } DocInfo6;
  38.  
  39.  
  40. typedef struct        /* information array element */
  41. {
  42.     int        height;
  43.     int        pagePos;
  44.     long    **paraHand;
  45.     union
  46.     {
  47.         Byte    st;        /* first byte is status */
  48.         long    pos;
  49.     } stPos;
  50.     int        dataLength;
  51.     int        formats;
  52. } ParaInfo6, InfoArray[];
  53.  
  54.  
  55.  
  56. SFReply    outReply;                /* output file */
  57. SFReply    theStream;                /* SFGetFile reply record */
  58. Boolean    streamOpen = false;        /* whether stream currently open */
  59. int        streamType;                /* file type of stream */
  60. int        f;                        /* input file reference number */
  61.  
  62.  
  63. /*  vars needed for TEXT stream only */
  64.  
  65. char    filBuf[bufSize];    /* file buffer */
  66. long    fLen;
  67. int        fChars;
  68.  
  69. /*  vars needed for WORD stream only */
  70.  
  71. ByteBuf        **paraBuf = nil;
  72. InfoArray    **infoHand = nil;
  73. Boolean        compressed;
  74. Boolean        inPara;
  75. int            nParas;        /* number of paragraphs */
  76. int            paraNum;    /* current paragraph number */
  77. int            pIndex;        /* index into paragraph */
  78. int            pChars;        /* number of chars extracted from paragraph */
  79. int            pLen;        /* number of chars in paragraph */
  80.  
  81. /* decompression variables */
  82.  
  83. Boolean    firstHalf;    /* which half of current index char */
  84. Boolean    needNib;    /* true = 2nd nibble needed for ascii */
  85. Boolean    nextAsc;    /* true = two nibbles needed */
  86. Byte    lastNib;    /* holds last nibble */
  87.  
  88. /* miscellaneous */
  89.  
  90. Point    dlogWhere = { 70 /* = y */, 100 /* = x */ };
  91. OSType    type[2] = { 'WORD', 'TEXT' };
  92.  
  93.  
  94. MyFRead (p, amount)
  95. Ptr        p;
  96. long    amount;
  97.     (void) FSRead (f, &amount, p);
  98. }
  99.  
  100. MyFSeek (pos)
  101. long    pos;
  102. {
  103.     (void) SetFPos (f, fsFromStart, pos);
  104. }
  105.  
  106.  
  107. /*
  108.     _FSOpen - like FSOpen, but has open mode parameter.
  109.  
  110.     CloseStream - close current stream, if one is open.  Releases any
  111.         heap storage currently used, if stream is WORD type.
  112.  
  113.     OpenStream - open 'TEXT' or 'WORD' stream.
  114.         Return noErr if file opened OK, fnOpnErr or mFulErr if not.
  115.         if OK, set fileOpen true.
  116. */
  117.  
  118.  
  119. OSErr _FSOpen (fName, vRefNum, refNum, mode)
  120. StringPtr    fName;
  121. int            vRefNum;
  122. int            *refNum;
  123. int            mode;
  124. {
  125. ParamBlockRec    p;
  126. register OSErr    result;
  127.  
  128.     p.ioParam.ioNamePtr = fName;
  129.     p.ioParam.ioVRefNum = vRefNum;
  130.     p.ioParam.ioPermssn = mode;
  131.     p.ioParam.ioVersNum = 0;
  132.     p.ioParam.ioMisc = 0;
  133.     result = PBOpen (&p, false);
  134.     *refNum = p.ioParam.ioRefNum;
  135.     return (result);
  136. }
  137.  
  138.  
  139. CloseStream ()
  140. {
  141.     if (streamOpen)
  142.     {
  143.         (void) FSClose (f);
  144.         /*(void) FlushVol (nil, theStream.vRefNum);*/
  145.         streamOpen = false;
  146.         if (paraBuf != nil)
  147.         {
  148.             DisposHandle (paraBuf);
  149.             paraBuf = nil;
  150.         }
  151.         if (infoHand != nil)
  152.         {
  153.             DisposHandle (infoHand);
  154.             infoHand = nil;
  155.         }
  156.     }
  157. }
  158.  
  159.  
  160. OSErr OpenStream ()
  161. {
  162. DocInfo3        docInfo3;
  163. DocInfo6        docInfo6;
  164. register OSErr    result = fnOpnErr;
  165. register int    curRes;
  166.  
  167.     CloseStream ();            /* close any currently open stream */
  168.  
  169.     curRes = CurResFile ();
  170.     UseResFile (0);
  171.     SFGetFile (dlogWhere, "\p", nil, 2, &type, nil, &theStream);
  172.     UseResFile (curRes);
  173.     Update ();                /* refresh screen immediately */
  174.     if (theStream.good)
  175.     {
  176.         if (_FSOpen (theStream.fName, theStream.vRefNum,
  177.                                     &f, fsRdPerm) == noErr)
  178.         {
  179.             streamOpen = true;
  180.             result = noErr;
  181.         }
  182.     }
  183.  
  184.     if (result == noErr)        /* so far, so good */
  185.     {
  186.         if (theStream.fType == 'TEXT')
  187.         {
  188.             streamType = text;
  189.             fChars = 0;    /* set these to trigger a read on the first */
  190.             fLen = 0;    /* call to StreamGetC() */
  191.         }
  192.         else    /* must be WORD file - determine version */
  193.         {
  194.             paraBuf = (ByteBuf **) NewHandle (0L);
  195.             MyFRead (&docInfo3, (long) sizeof (DocInfo3));
  196.  
  197.             if (docInfo3.version == 3)        /* MacWrite 2.2 file */
  198.             {
  199.                 streamType = mwrt3;
  200.                 nParas = docInfo3.paraCount;
  201.                 MyFSeek ((long) docInfo3.paraOffset);
  202.             }
  203.             else if (docInfo3.version == 6)    /* MacWrite 4.5 file */
  204.             {
  205.                 streamType = mwrt6;
  206.                 MyFSeek (264L);        /* 252 + 12 */
  207.                 MyFRead (&docInfo6, (long) sizeof (DocInfo6));
  208.                 MyFSeek (docInfo6.iArrayPos);
  209.                 infoHand = (InfoArray **) NewHandle (docInfo6.iArrayLen);
  210.                 if (infoHand == nil)
  211.                 {
  212.                     CloseStream ();
  213.                     result = mFulErr;
  214.                 }
  215.                 else
  216.                 {
  217.                     HLock (infoHand);
  218.                     MyFRead (*infoHand, (long) docInfo6.iArrayLen);
  219.                     HUnlock (infoHand);
  220.                     nParas = docInfo6.iArrayLen / sizeof (ParaInfo6);
  221.                 }
  222.             }
  223.             else
  224.             {
  225.                 CloseStream ();
  226.                 Alarm ("\pFile created by unsupported MacWrite version");
  227.                 result = fnOpnErr;
  228.             }
  229.             paraNum = -1;
  230.             inPara = false;            /* not in any paragraph yet */
  231.         }
  232.     }
  233.     return (result);
  234. }
  235.  
  236.  
  237. Boolean GetStream ()
  238. {
  239.  
  240.     if (OpenStream () != noErr)
  241.         return (false);
  242.     DisplayString (theStream.fName);
  243.     DisplayString ("\p (");
  244.     DisplayString (streamType == text ? "\pText" : "\pMacWrite");
  245.     DisplayString ("\p file)\r");
  246.     return (true);
  247. }
  248.  
  249.  
  250. /*
  251.     _Decompress takes a nibble at a time of compressed text.  If more
  252.     nibbles are needed to complete the next character, return -1, else
  253.     returns the character.
  254. */
  255.        
  256. _Decompress (b)
  257. Byte    b;
  258. {
  259. register int    result = -1;
  260.  
  261.     if (needNib)                /* Low half of ascii nibble is needed. */
  262.     {
  263.         needNib = false;
  264.         result = lastNib | b;    /* Put the two halves together */
  265.     }
  266.     else if (nextAsc)            /* Two nibbles are needed */
  267.     {
  268.         nextAsc = false;
  269.         lastNib = b << 4;        /* Save this one as the high nibble */
  270.         needNib = true;            /* Need one more nibble */
  271.     }
  272.     else if (b == 15)            /* Nibble of 15 means the next char is ascii */
  273.         nextAsc = true;
  274.     else            /* Add the nibble value to the English decompression */
  275.                     /* key (saved as Resource Type 'STR ' 700 in file)   */
  276.                     /* to get the proper character */
  277.     {
  278.         result = " etnroaisdlhcfp" [b];    /* note: C string */
  279.     }
  280.     return (result);
  281. }
  282.  
  283.  
  284. Boolean ReadParaBuf ()
  285. {
  286.     SetHandleSize (paraBuf, pLen);        /* make big enough */
  287.     if (MemError () != noErr)
  288.     {
  289.         Alarm ("\pCan't read paragraph buffer");
  290.         paraNum = nParas;    /* force stream close and exit of GetC loop */
  291.         return (false);
  292.     }
  293.     HLock (paraBuf);
  294.     MyFRead (*paraBuf, (long) pLen);
  295.     HUnlock (paraBuf);
  296.     return (true);
  297. }
  298.  
  299.  
  300. WordStreamGetC ()        /* return -1 on EOF */
  301. {
  302. register int    c;
  303. register int    result;
  304. ParaInfo3        paraInfo3;
  305.  
  306.     if (!inPara)        /* must read in next paragraph */
  307.     {
  308.         for (;;)
  309.         {
  310.             if (++paraNum >= nParas)
  311.             {
  312.                 CloseStream ();
  313.                 return (-1);
  314.             }
  315.             if (streamType == mwrt3)
  316.             {
  317.                 MyFRead (¶Info3, (long) sizeof (ParaInfo3));
  318.                 pLen = paraInfo3.paraLen;
  319.                 if (ReadParaBuf () == false)
  320.                     continue;
  321.                 if (paraInfo3.paraType != 1)
  322.                 {
  323.                     continue;    /* not text */
  324.                 }
  325.                 /* adding two skips length word */
  326.                 if ((pLen = ((int *) **paraBuf)[0] + 2) == 2)
  327.                     continue;    /* empty paragraph */
  328.                 pChars = 2;
  329.                 compressed = false;
  330.                 inPara = true;
  331.                 break;
  332.             }
  333.             else    /* mwrt6 */
  334.             {
  335.                 if ((**infoHand)[paraNum].height <= 0)
  336.                 {
  337.                     continue;    /* not text */
  338.                 }
  339.  
  340. /*
  341.     Seek to this paragraph's data (must mask the high byte to get the
  342.     correct value).  Move to the paragraph, get its length, make
  343.     the pointer big enough, and read it in.  (skip to next para if this
  344.     one is empty, though.)
  345.     compressed will be set true if the paragraph is compressed.
  346. */
  347.  
  348.                 MyFSeek ((**infoHand)[paraNum].stPos.pos & 0x00FFFFFF);
  349.                 MyFRead (&pLen, (long) sizeof (int));    /* get length */
  350.                 if (pLen == 0)
  351.                 {
  352.                     continue;                        /* empty para - skip */
  353.                 }
  354.                 if (ReadParaBuf () == false)
  355.                     continue;
  356.                 compressed = ((**infoHand)[paraNum].stPos.st >> 3) & 1;
  357.                 inPara = true;
  358.                 nextAsc = false;
  359.                 needNib = false;
  360.                 pIndex = 0;        /* index into current paragraph */
  361.                 pChars = 0;        /* chars extracted from current paragraph */
  362.                 firstHalf = true;    /* use first half of current index char */
  363.                 break;
  364.             }
  365.         }
  366.     }
  367.  
  368. /*
  369.     At this point, know either that we have a new non-empty paragraph, or
  370.     are still in the previous one.
  371. */
  372.  
  373.     if (!compressed)    /* uncompressed */
  374.     {
  375.         c = (**paraBuf)[pChars];
  376.     }
  377.     else
  378.     {
  379.         do
  380.         {
  381.             c = (**paraBuf)[pIndex];
  382.             if (firstHalf)
  383.             {
  384.                 c = _Decompress (((Byte) c) >> 4);
  385.             }
  386.             else
  387.             {
  388.                 c = _Decompress ((Byte) (c & 0x0f));
  389.                 ++pIndex;    /* go to next char at next index */
  390.             }
  391.             firstHalf = !firstHalf;
  392.         } while (c == -1);
  393.     }
  394.     if (++pChars >= pLen)    /* see if need new paragraph next time */
  395.         inPara = false;
  396.     return (c);
  397. }
  398.  
  399.  
  400. /*
  401.     StreamGetC - get character from stream.
  402. */
  403.  
  404. StreamGetC ()
  405. {
  406.  
  407.     if (!streamOpen)
  408.         return (-1);
  409.  
  410.     if (streamType != text)
  411.         return (WordStreamGetC ());
  412.  
  413.     if (fChars >= fLen)    /* need to read in a new block */
  414.     {
  415.         fLen = bufSize;
  416.         (void) FSRead (f, &fLen, filBuf);
  417.         if (fLen == 0)
  418.         {
  419.             CloseStream ();
  420.             return (-1);
  421.         }
  422.         fChars = 0;
  423.     }
  424.     return (filBuf[fChars++]);
  425. }
  426.  
  427.  
  428. /*
  429.     StreamGetS - get string from stream.
  430.  
  431.     Returns nil if no string obtained, otherwise a pointer to the argument.
  432. */
  433.  
  434. StringPtr StreamGetS (s)
  435. register StringPtr    s;
  436. {
  437. register int        c;
  438. register StringPtr    result = nil;
  439.  
  440.     s[0] = 0;    /* clear string */
  441.     while ((c = StreamGetC ()) != -1)
  442.     {
  443.         result = s;    /* got something, so StreamGetS succeeds */
  444.         if (c == '\r' || (s[0] > lineLen && c == ' '))
  445.             break;
  446.         s[++s[0]] = c;        /* add char to end */
  447.     }
  448.     return (result);
  449. }
  450.  
  451.  
  452.  
  453. FileOutput ()
  454. {
  455. FInfo                f;
  456. long                pos;
  457. register int        curRes;
  458.  
  459.     if (fileOpen)    /* close it */
  460.     {
  461.         fileOpen = false;
  462.         (void) GetFPos (outFile, &pos);
  463.         (void) SetEOF (outFile, pos);
  464.         (void) FSClose (outFile);
  465.         (void) FlushVol (nil, outReply.vRefNum);
  466.         SetItem (theMenu, saveOutput, "\pSave Output...");
  467.     }
  468.     else
  469.     {
  470.         curRes = CurResFile ();
  471.         UseResFile (0);
  472.         SFPutFile (dlogWhere, "\pWrite To...", "\p", nil, &outReply);
  473.         UseResFile (curRes);
  474.         Update ();            /* refresh screen immediately */
  475.         if (outReply.good)
  476.         {
  477.             if (GetFInfo (outReply.fName, outReply.vRefNum, &f) == noErr) /* exists */
  478.             {
  479.                 if (f.fdType != 'TEXT')
  480.                 {
  481.                     Alarm ("\pNot a TEXT File");
  482.                     return;
  483.                 }
  484.             }
  485.             else    /* doesn't exist.  create it. */
  486.             {
  487.                 if (Create (outReply.fName, outReply.vRefNum,
  488.                             'Grep', 'TEXT') != noErr)
  489.                 {
  490.                     Alarm ("\pCan't Create");
  491.                     return;
  492.                 }
  493.             }
  494.  
  495.             if (_FSOpen (outReply.fName, outReply.vRefNum,
  496.                                 &outFile, fsWrPerm) != noErr)
  497.                 Alarm ("\pCan't Open");
  498.             else
  499.             {
  500.                 fileOpen = true;
  501.                 SetItem (theMenu, saveOutput, "\pStop Saving Output");
  502.             }
  503.         }
  504.     }
  505. }
  506.